using Core;
using Microsoft.Extensions.Options;
using SuperSocket;
using SuperSocket.Server;

namespace Server;

public sealed class PlayServer : SuperSocketService<PlayPacket>
{
    private readonly PacketDispatchOptions _dispatchOptions;
    private readonly IAsyncSessionContainer _sessionContainer;

    public PlayServer(
        IServiceProvider serviceProvider, 
        IOptions<ServerOptions> serverOptions,
        IOptions<PacketDispatchOptions> dispatchOptions)
        : base(serviceProvider, serverOptions)
    {
        _dispatchOptions = dispatchOptions.Value;
        _sessionContainer = this.GetAsyncSessionContainer();
    }

    internal ValueTask<OrderRespPacket> AddOrderAsync(OrderPacket packet)
    {
        return SendAndReceivePacketAsync<OrderRespPacket>(packet.TargetId, packet);
    }

    internal async ValueTask<TRespPacket> SendAndReceivePacketAsync<TRespPacket>(
        ulong targetId,
        PlayPacketWithIdentifier packet)
        where TRespPacket : PlayPacketWithIdentifier
    {
        var sessions = await _sessionContainer.GetSessionsAsync<PlaySession>(s => s.UserId == targetId);

        if (sessions == null)
            throw new OffLineException($"{targetId} 对方已离线");

        if (!sessions.Any())
            throw new OffLineException($"{targetId} 对方已离线");

        var session = sessions.First();

        using var source = new CancellationTokenSource(TimeSpan.FromSeconds(_dispatchOptions.Timeout));

        return await session.SendAndReceivePacketAsync<TRespPacket>(packet, source.Token);
    }
}